home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 126-150 / disk_147 / src / line.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  16KB  |  610 lines

  1. /*
  2.  *        Text line handling.
  3.  * The functions in this file
  4.  * are a general set of line management
  5.  * utilities. They are the only routines that
  6.  * touch the text. They also touch the buffer
  7.  * and window structures, to make sure that the
  8.  * necessary updating gets done. There are routines
  9.  * in this file that handle the kill buffer too.
  10.  * It isn't here for any good reason.
  11.  *
  12.  * Note that this code only updates the dot and
  13.  * mark values in the window list. Since all the code
  14.  * acts on the current window, the buffer that we
  15.  * are editing must be being displayed, which means
  16.  * that "b_nwnd" is non zero, which means that the
  17.  * dot and mark values in the buffer headers are
  18.  * nonsense.
  19.  */
  20. #include    "def.h"
  21.  
  22. /* number of bytes member is from start of structure type    */
  23. /* should be computed at compile time                */
  24.  
  25. #ifndef OFFSET
  26. #define OFFSET(type,member) ((char *)&(((type *)0)->member)-(char *)((type *)0))
  27. #endif
  28.  
  29. #ifndef NBLOCK
  30. #define NBLOCK    16            /* Line block chunk size    */
  31. #endif
  32.  
  33. #ifndef KBLOCK
  34. #define KBLOCK    256            /* Kill buffer block size.    */
  35. #endif
  36.  
  37. static char    *kbufp    = NULL;        /* Kill buffer data.        */
  38. static RSIZE    kused    = 0;        /* # of bytes used in KB.    */
  39. static RSIZE    ksize    = 0;        /* # of bytes allocated in KB.    */
  40. static RSIZE    kstart    = 0;        /* # of first used byte in KB.    */
  41.  
  42. /*
  43.  * This routine allocates a block of memory large enough to hold a LINE
  44.  * containing "used" characters. The block is rounded up to whatever
  45.  * needs to be allocated. (use lallocx for lines likely to grow.)
  46.  * Return a pointer to the new block, or NULL if there isn't
  47.  * any memory left. Print a message in the message line if no space.
  48.  */
  49. LINE *
  50. lalloc(used) register int used; {
  51.     register LINE    *lp;
  52.     register int    size;
  53.  
  54.     /* any padding at the end of the structure is used */
  55.     if((size = used + OFFSET(LINE, l_text[0])) < sizeof(LINE))
  56.         size = sizeof(LINE);
  57. #ifdef MALLOCROUND
  58.     MALLOCROUND(size);    /* round up to a size optimal to malloc */
  59. #endif
  60.     if((lp = (LINE *)malloc((unsigned)size)) == NULL) {
  61.         ewprintf("Can't get %d bytes", size);
  62.         return (LINE *)NULL;
  63.     }
  64.     lp->l_size = size - OFFSET(LINE, l_text[0]);
  65.     lp->l_used = used;
  66.     return lp;
  67. }
  68.  
  69. /*
  70.  * Like lalloc, only round amount desired up because this line will
  71.  * probably grow.  We always make room for at least one more char.
  72.  * (thus making 0 not a special case anymore.)
  73.  */
  74. LINE *
  75. lallocx(used)
  76. int used;
  77. {
  78.     register int size;
  79.     register LINE *lp;
  80.  
  81.     size = (NBLOCK+used) & ~(NBLOCK-1);
  82.     if((lp = lalloc(size)) != NULL) lp->l_used = used;
  83.     return lp;
  84. }
  85.  
  86. /*
  87.  * Delete line "lp". Fix all of the
  88.  * links that might point at it (they are
  89.  * moved to offset 0 of the next line.
  90.  * Unlink the line from whatever buffer it
  91.  * might be in. Release the memory. The
  92.  * buffers are updated too; the magic conditions
  93.  * described in the above comments don't hold
  94.  * here.
  95.  */
  96. VOID
  97. lfree(lp) register LINE *lp; {
  98.     register BUFFER *bp;
  99.     register WINDOW *wp;
  100.  
  101.     for(wp = wheadp; wp != NULL; wp = wp->w_wndp) {
  102.         if (wp->w_linep == lp)
  103.             wp->w_linep = lp->l_fp;
  104.         if (wp->w_dotp    == lp) {
  105.             wp->w_dotp  = lp->l_fp;
  106.             wp->w_doto  = 0;
  107.         }
  108.         if (wp->w_markp == lp) {
  109.             wp->w_markp = lp->l_fp;
  110.             wp->w_marko = 0;
  111.         }
  112.     }
  113.     for(bp = bheadp; bp != NULL; bp = bp->b_bufp) {
  114.         if (bp->b_nwnd == 0) {
  115.             if (bp->b_dotp    == lp) {
  116.                 bp->b_dotp = lp->l_fp;
  117.                 bp->b_doto = 0;
  118.             }
  119.             if (bp->b_markp == lp) {
  120.                 bp->b_markp = lp->l_fp;
  121.                 bp->b_marko = 0;
  122.             }
  123.         }
  124.     }
  125.     lp->l_bp->l_fp = lp->l_fp;
  126.     lp->l_fp->l_bp = lp->l_bp;
  127.     free((char *) lp);
  128. }
  129.  
  130. /*
  131.  * This routine gets called when
  132.  * a character is changed in place in the
  133.  * current buffer. It updates all of the required
  134.  * flags in the buffer and window system. The flag
  135.  * used is passed as an argument; if the buffer is being
  136.  * displayed in more than 1 window we change EDIT to
  137.  * HARD. Set MODE if the mode line needs to be
  138.  * updated (the "*" has to be set).
  139.  */
  140. VOID
  141. lchange(flag) register int flag; {
  142.     register WINDOW *wp;
  143.  
  144.     if ((curbp->b_flag&BFCHG) == 0) {    /* First change, so    */
  145.         flag |= WFMODE;            /* update mode lines.    */
  146.         curbp->b_flag |= BFCHG;
  147.     }
  148.     for(wp = wheadp; wp != NULL; wp = wp->w_wndp) {
  149.         if (wp->w_bufp == curbp) {
  150.             wp->w_flag |= flag;
  151.             if(wp != curwp) wp->w_flag |= WFHARD;
  152.         }
  153.     }
  154. }
  155.  
  156. /*
  157.  * Insert "n" copies of the character "c"
  158.  * at the current location of dot. In the easy case
  159.  * all that happens is the text is stored in the line.
  160.  * In the hard case, the line has to be reallocated.
  161.  * When the window list is updated, take special
  162.  * care; I screwed it up once. You always update dot
  163.  * in the current window. You update mark, and a
  164.  * dot in another window, if it is greater than
  165.  * the place where you did the insert. Return TRUE
  166.  * if all is well, and FALSE on errors.
  167.  */
  168. linsert(n, c)
  169. int n;
  170. {
  171.     register char    *cp1;
  172.     register char    *cp2;
  173.     register LINE    *lp1;
  174.     LINE        *lp2;
  175.     LINE        *lp3;
  176.     register int    doto;
  177.     register RSIZE    i;
  178.     WINDOW        *wp;
  179.  
  180.     lchange(WFEDIT);
  181.     lp1 = curwp->w_dotp;            /* Current line        */
  182.     if (lp1 == curbp->b_linep) {        /* At the end: special    */
  183.             /* (now should only happen in empty buffer    */
  184.         if (curwp->w_doto != 0) {
  185.             ewprintf("bug: linsert");
  186.             return FALSE;
  187.         }
  188.         if ((lp2=lallocx(n)) == NULL) /* Allocate new line */
  189.             return FALSE;
  190.         lp3 = lp1->l_bp;        /* Previous line    */
  191.         lp3->l_fp = lp2;        /* Link in        */
  192.         lp2->l_fp = lp1;
  193.         lp1->l_bp = lp2;
  194.         lp2->l_bp = lp3;
  195.         for (i=0; i<n; ++i)
  196.             lp2->l_text[i] = c;
  197.         for(wp = wheadp; wp != NULL; wp = wp->w_wndp) {
  198.             if (wp->w_linep == lp1)
  199.                 wp->w_linep = lp2;
  200.             if (wp->w_dotp == lp1)
  201.                 wp->w_dotp = lp2;
  202.             if (wp->w_markp == lp1)
  203.                 wp->w_markp = lp2;
  204.         }
  205.         /*NOSTRICT*/
  206.         curwp->w_doto = n;
  207.         return TRUE;
  208.     }
  209.     doto = curwp->w_doto;            /* Save for later.    */
  210.     /*NOSTRICT (2) */
  211.     if (lp1->l_used+n > lp1->l_size) {    /* Hard: reallocate    */
  212.         if ((lp2=lallocx(lp1->l_used+n)) == NULL)
  213.             return FALSE;
  214.         cp1 = &lp1->l_text[0];
  215.         cp2 = &lp2->l_text[0];
  216.         while (cp1 != &lp1->l_text[doto])
  217.             *cp2++ = *cp1++;
  218.         /*NOSTRICT*/
  219.         cp2 += n;
  220.         while (cp1 != &lp1->l_text[lp1->l_used])
  221.             *cp2++ = *cp1++;
  222.         lp1->l_bp->l_fp = lp2;
  223.         lp2->l_fp = lp1->l_fp;
  224.         lp1->l_fp->l_bp = lp2;
  225.         lp2->l_bp = lp1->l_bp;
  226.         free((char *) lp1);
  227.     } else {                /* Easy: in place    */
  228.         lp2 = lp1;            /* Pretend new line    */
  229.         /*NOSTRICT*/
  230.         lp2->l_used += n;
  231.         cp2 = &lp1->l_text[lp1->l_used];
  232.  
  233.         cp1 = cp2-n;
  234.         while (cp1 != &lp1->l_text[doto])
  235.             *--cp2 = *--cp1;
  236.     }
  237.     for (i=0; i<n; ++i)            /* Add the characters    */
  238.         lp2->l_text[doto+i] = c;
  239.  
  240.     for(wp = wheadp; wp != NULL; wp = wp->w_wndp) {
  241.         if (wp->w_linep == lp1)
  242.             wp->w_linep = lp2;
  243.         if (wp->w_dotp == lp1) {
  244.             wp->w_dotp = lp2;
  245.             if (wp==curwp || wp->w_doto>doto)
  246.                 /*NOSTRICT*/
  247.                 wp->w_doto += n;
  248.         }
  249.         if (wp->w_markp == lp1) {
  250.             wp->w_markp = lp2;
  251.             if (wp->w_marko > doto)
  252.                 /*NOSTRICT*/
  253.                 wp->w_marko += n;
  254.         }
  255.     }
  256.     return TRUE;
  257. }
  258.  
  259. /*
  260.  * Insert a newline into the buffer
  261.  * at the current location of dot in the current
  262.  * window.  The funny ass-backwards way is no longer used.
  263.  */
  264. lnewline()
  265. {
  266.     register LINE    *lp1;
  267.     register LINE    *lp2;
  268.     register int    doto;
  269.     register int    nlen;
  270.     WINDOW        *wp;
  271.  
  272.     lchange(WFHARD);
  273.     lp1  = curwp->w_dotp;            /* Get the address and    */
  274.     doto = curwp->w_doto;            /* offset of "."    */
  275.     if(doto == 0) {                /* avoid unnessisary copying */
  276.         if((lp2 = lallocx(0)) == NULL)    /* new first part    */
  277.             return FALSE;
  278.         lp2->l_bp = lp1->l_bp;
  279.         lp1->l_bp->l_fp = lp2;
  280.         lp2->l_fp = lp1;
  281.         lp1->l_bp = lp2;
  282.         for(wp = wheadp; wp!=NULL; wp = wp->w_wndp)
  283.             if(wp->w_linep == lp1) wp->w_linep = lp2;
  284.         return    TRUE;
  285.     }
  286.     nlen = llength(lp1) - doto;        /* length of new part    */
  287.     if((lp2=lallocx(nlen)) == NULL)        /* New second half line */
  288.         return FALSE;
  289.     if(nlen!=0) bcopy(&lp1->l_text[doto], &lp2->l_text[0], nlen);
  290.     lp1->l_used = doto;
  291.     lp2->l_bp = lp1;
  292.     lp2->l_fp = lp1->l_fp;
  293.     lp1->l_fp = lp2;
  294.     lp2->l_fp->l_bp = lp2;
  295.     for(wp = wheadp; wp != NULL; wp = wp->w_wndp) { /* Windows    */
  296.         if (wp->w_dotp == lp1 && wp->w_doto >= doto) {
  297.             wp->w_dotp = lp2;
  298.             wp->w_doto -= doto;
  299.         }
  300.         if (wp->w_markp == lp1 && wp->w_marko >= doto) {
  301.             wp->w_markp = lp2;
  302.             wp->w_marko -= doto;
  303.         }
  304.     }
  305.     return TRUE;
  306. }
  307.  
  308. /*
  309.  * This function deletes "n" bytes,
  310.  * starting at dot. It understands how do deal
  311.  * with end of lines, etc. It returns TRUE if all
  312.  * of the characters were deleted, and FALSE if
  313.  * they were not (because dot ran into the end of
  314.  * the buffer. The "kflag" indicates either no insertion,
  315.  * or direction of insertion into the kill buffer.
  316.  */
  317. ldelete(n, kflag) RSIZE n; {
  318.     register char    *cp1;
  319.     register char    *cp2;
  320.     register LINE    *dotp;
  321.     register int    doto;
  322.     register RSIZE    chunk;
  323.     WINDOW        *wp;
  324.  
  325.     /*
  326.      * HACK - doesn't matter, and fixes back-over-nl bug for empty
  327.      *    kill buffers.
  328.      */
  329.     if (kused == kstart) kflag = KFORW;
  330.  
  331.     while (n != 0) {
  332.         dotp = curwp->w_dotp;
  333.         doto = curwp->w_doto;
  334.         if (dotp == curbp->b_linep)    /* Hit end of buffer.    */
  335.             return FALSE;
  336.         chunk = dotp->l_used-doto;    /* Size of chunk.    */
  337.         if (chunk > n)
  338.             chunk = n;
  339.         if (chunk == 0) {        /* End of line, merge.    */
  340.             if(dotp == lback(curbp->b_linep))
  341.                 return FALSE;    /* End of buffer.    */
  342.             lchange(WFHARD);
  343.             if (ldelnewline() == FALSE
  344.             || (kflag!=KNONE && kinsert('\n', kflag)==FALSE))
  345.                 return FALSE;
  346.             --n;
  347.             continue;
  348.         }
  349.         lchange(WFEDIT);
  350.         cp1 = &dotp->l_text[doto];    /* Scrunch text.    */
  351.         cp2 = cp1 + chunk;
  352.         if (kflag == KFORW) {
  353.             while (ksize - kused < chunk)
  354.                 if (kgrow(FALSE) == FALSE) return FALSE;
  355.             bcopy(cp1, &(kbufp[kused]), (int) chunk);
  356.             kused += chunk;
  357.         } else if (kflag == KBACK) {
  358.             while (kstart < chunk)
  359.                 if (kgrow(TRUE) == FALSE) return FALSE;
  360.             bcopy(cp1, &(kbufp[kstart-chunk]), (int) chunk);
  361.             kstart -= chunk;
  362.         } else if (kflag != KNONE) panic("broken ldelete call");
  363.         while (cp2 != &dotp->l_text[dotp->l_used])
  364.             *cp1++ = *cp2++;
  365.         dotp->l_used -= (int) chunk;
  366.         for(wp = wheadp; wp != NULL; wp = wp->w_wndp ) {
  367.             if (wp->w_dotp==dotp && wp->w_doto>=doto) {
  368.                 /*NOSTRICT*/
  369.                 wp->w_doto -= chunk;
  370.                 if (wp->w_doto < doto)
  371.                     wp->w_doto = doto;
  372.             }
  373.             if (wp->w_markp==dotp && wp->w_marko>=doto) {
  374.                 /*NOSTRICT*/
  375.                 wp->w_marko -= chunk;
  376.                 if (wp->w_marko < doto)
  377.                     wp->w_marko = doto;
  378.             }
  379.         }
  380.         n -= chunk;
  381.     }
  382.     return TRUE;
  383. }
  384.  
  385. /*
  386.  * Delete a newline. Join the current line
  387.  * with the next line. If the next line is the magic
  388.  * header line always return TRUE; merging the last line
  389.  * with the header line can be thought of as always being a
  390.  * successful operation, even if nothing is done, and this makes
  391.  * the kill buffer work "right". Easy cases can be done by
  392.  * shuffling data around. Hard cases require that lines be moved
  393.  * about in memory. Return FALSE on error and TRUE if all
  394.  * looks ok.
  395.  */
  396. ldelnewline() {
  397.     register LINE    *lp1;
  398.     register LINE    *lp2;
  399.     register WINDOW *wp;
  400.     LINE        *lp3;
  401.  
  402.     lp1 = curwp->w_dotp;
  403.     lp2 = lp1->l_fp;
  404.     if (lp2 == curbp->b_linep)        /* At the buffer end.    */
  405.         return TRUE;
  406.     if (lp2->l_used <= lp1->l_size - lp1->l_used) {
  407.         bcopy(&lp2->l_text[0], &lp1->l_text[lp1->l_used], lp2->l_used);
  408.         for(wp = wheadp; wp != NULL; wp = wp->w_wndp) {
  409.             if (wp->w_linep == lp2)
  410.                 wp->w_linep = lp1;
  411.             if (wp->w_dotp == lp2) {
  412.                 wp->w_dotp  = lp1;
  413.                 wp->w_doto += lp1->l_used;
  414.             }
  415.             if (wp->w_markp == lp2) {
  416.                 wp->w_markp  = lp1;
  417.                 wp->w_marko += lp1->l_used;
  418.             }
  419.         }
  420.         lp1->l_used += lp2->l_used;
  421.         lp1->l_fp = lp2->l_fp;
  422.         lp2->l_fp->l_bp = lp1;
  423.         free((char *) lp2);
  424.         return TRUE;
  425.     }
  426.     if ((lp3=lalloc(lp1->l_used + lp2->l_used)) == NULL)
  427.         return FALSE;
  428.     bcopy(&lp1->l_text[0], &lp3->l_text[0], lp1->l_used);
  429.     bcopy(&lp2->l_text[0], &lp3->l_text[lp1->l_used], lp2->l_used);
  430.     lp1->l_bp->l_fp = lp3;
  431.     lp3->l_fp = lp2->l_fp;
  432.     lp2->l_fp->l_bp = lp3;
  433.     lp3->l_bp = lp1->l_bp;
  434.     for(wp = wheadp; wp != NULL; wp = wp->w_wndp) {
  435.         if (wp->w_linep==lp1 || wp->w_linep==lp2)
  436.             wp->w_linep = lp3;
  437.         if (wp->w_dotp == lp1)
  438.             wp->w_dotp  = lp3;
  439.         else if (wp->w_dotp == lp2) {
  440.             wp->w_dotp  = lp3;
  441.             wp->w_doto += lp1->l_used;
  442.         }
  443.         if (wp->w_markp == lp1)
  444.             wp->w_markp  = lp3;
  445.         else if (wp->w_markp == lp2) {
  446.             wp->w_markp  = lp3;
  447.             wp->w_marko += lp1->l_used;
  448.         }
  449.     }
  450.     free((char *) lp1);
  451.     free((char *) lp2);
  452.     return TRUE;
  453. }
  454.  
  455. /*
  456.  * Replace plen characters before dot with argument string.
  457.  * Control-J characters in st are interpreted as newlines.
  458.  * There is a casehack disable flag (normally it likes to match
  459.  * case of replacement to what was there).
  460.  */
  461. lreplace(plen, st, f)
  462. register RSIZE    plen;            /* length to remove        */
  463. char        *st;            /* replacement string        */
  464. int        f;            /* case hack disable        */
  465. {
  466.     register RSIZE    rlen;        /* replacement length        */
  467.     register int    rtype;        /* capitalization        */
  468.     register int    c;        /* used for random characters    */
  469.     register int    doto;        /* offset into line        */
  470.  
  471.     /*
  472.      * Find the capitalization of the word that was found.
  473.      * f says use exact case of replacement string (same thing that
  474.      * happens with lowercase found), so bypass check.
  475.      */
  476.     /*NOSTRICT*/
  477.     (VOID) backchar(FFARG | FFRAND, (int) plen);
  478.     rtype = _L;
  479.     c = lgetc(curwp->w_dotp, curwp->w_doto);
  480.     if (ISUPPER(c)!=FALSE  &&  f==FALSE) {
  481.         rtype = _U|_L;
  482.         if (curwp->w_doto+1 < llength(curwp->w_dotp)) {
  483.             c = lgetc(curwp->w_dotp, curwp->w_doto+1);
  484.             if (ISUPPER(c) != FALSE) {
  485.                 rtype = _U;
  486.             }
  487.         }
  488.     }
  489.  
  490.     /*
  491.      * make the string lengths match (either pad the line
  492.      * so that it will fit, or scrunch out the excess).
  493.      * be careful with dot's offset.
  494.      */
  495.     rlen = strlen(st);
  496.     doto = curwp->w_doto;
  497.     if (plen > rlen)
  498.         (VOID) ldelete((RSIZE) (plen-rlen), KNONE);
  499.     else if (plen < rlen) {
  500.         if (linsert((int)(rlen-plen), ' ') == FALSE)
  501.             return FALSE;
  502.     }
  503.     curwp->w_doto = doto;
  504.  
  505.     /*
  506.      * do the replacement:    If was capital, then place first
  507.      * char as if upper, and subsequent chars as if lower.
  508.      * If inserting upper, check replacement for case.
  509.      */
  510.     while ((c = CHARMASK(*st++)) != '\0') {
  511.         if ((rtype&_U)!=0  &&  ISLOWER(c)!=0)
  512.             c = TOUPPER(c);
  513.         if (rtype == (_U|_L))
  514.             rtype = _L;
  515.         if (c == CCHR('J')) {
  516.             if (curwp->w_doto == llength(curwp->w_dotp))
  517.                 (VOID) forwchar(FFRAND, 1);
  518.             else {
  519.                 if (ldelete((RSIZE) 1, KNONE) != FALSE)
  520.                     (VOID) lnewline();
  521.             }
  522.         } else if (curwp->w_dotp == curbp->b_linep) {
  523.             (VOID) linsert(1, c);
  524.         } else if (curwp->w_doto == llength(curwp->w_dotp)) {
  525.             if (ldelete((RSIZE) 1, KNONE) != FALSE)
  526.                 (VOID) linsert(1, c);
  527.         } else
  528.             lputc(curwp->w_dotp, curwp->w_doto++, c);
  529.     }
  530.     lchange(WFHARD);
  531.     return (TRUE);
  532. }
  533.  
  534. /*
  535.  * Delete all of the text
  536.  * saved in the kill buffer. Called by commands
  537.  * when a new kill context is being created. The kill
  538.  * buffer array is released, just in case the buffer has
  539.  * grown to immense size. No errors.
  540.  */
  541. VOID
  542. kdelete() {
  543.     if (kbufp != NULL) {
  544.         free((char *) kbufp);
  545.         kbufp = NULL;
  546.         kstart = kused = ksize = 0;
  547.     }
  548. }
  549.  
  550. /*
  551.  * Insert a character to the kill buffer,
  552.  * enlarging the buffer if there isn't any room. Always
  553.  * grow the buffer in chunks, on the assumption that if you
  554.  * put something in the kill buffer you are going to put
  555.  * more stuff there too later. Return TRUE if all is
  556.  * well, and FALSE on errors. Print a message on
  557.  * errors. Dir says whether to put it at back or front.
  558.  */
  559. kinsert(c, dir) {
  560.  
  561.     if (kused == ksize && dir == KFORW && kgrow(FALSE) == FALSE)
  562.         return FALSE;
  563.     if (kstart == 0 && dir == KBACK && kgrow(TRUE) == FALSE)
  564.         return FALSE;
  565.     if (dir == KFORW) kbufp[kused++] = c;
  566.     else if (dir == KBACK) kbufp[--kstart] = c;
  567.     else panic("broken kinsert call");        /* Oh shit! */
  568.     return (TRUE);
  569. }
  570.  
  571. /*
  572.  * kgrow - just get more kill buffer for the callee. back is true if
  573.  * we are trying to get space at the beginning of the kill buffer.
  574.  */
  575. kgrow(back) {
  576.     register int    nstart;
  577.     register char    *nbufp;
  578.  
  579.     if ((unsigned)(ksize+KBLOCK) <= (unsigned)ksize) {
  580.         /* probably 16 bit unsigned */
  581.         ewprintf("Kill buffer size at maximum");
  582.         return FALSE;
  583.     }
  584.     if ((nbufp=malloc((unsigned)(ksize+KBLOCK))) == NULL) {
  585.         ewprintf("Can't get %ld bytes", (long)(ksize+KBLOCK));
  586.         return FALSE;
  587.     }
  588.     nstart = (back == TRUE) ? (kstart + KBLOCK) : (KBLOCK / 4) ;
  589.     bcopy(&(kbufp[kstart]), &(nbufp[nstart]), (int) (kused-kstart));
  590.     if (kbufp != NULL)
  591.         free((char *) kbufp);
  592.     kbufp  = nbufp;
  593.     ksize += KBLOCK;
  594.     kused = kused - kstart + nstart;
  595.     kstart = nstart;
  596.     return TRUE;
  597. }
  598.  
  599. /*
  600.  * This function gets characters from
  601.  * the kill buffer. If the character index "n" is
  602.  * off the end, it returns "-1". This lets the caller
  603.  * just scan along until it gets a "-1" back.
  604.  */
  605. kremove(n) {
  606.     if (n < 0 || n + kstart >= kused)
  607.         return -1;
  608.     return CHARMASK(kbufp[n + kstart]);
  609. }
  610.